import math
import tkinter
from functools import partial
from tkinter import filedialog
import tkinter as tk
from tkinter.constants import HORIZONTAL, NW
from tkinter.messagebox import showinfo
from tkinter.ttk import Combobox

import cv2
import numpy as np
from PIL import Image, ImageTk, ImageEnhance, ImageOps

from DraggableText.DraggableText import DraggableText
from src.newton_method import equation
from src.Curve_toning import CurvesAdjustment
# 导入UI 将 Controller 的属性 ui 类型设置成 Win
from ui import Win, CustomCanvas
import scipy.optimize as opt


class Controller:
    # 导入UI类后，替换以下的 object 类型，将获得 IDE 属性提示功能
    ui: Win

    def __init__(self):
        self.watermark_image_back = None
        self.start_y = 0
        self.start_x = 0
        self.adjusted_image = None
        self.photo = None
        self.image_path_label = None
        self.image = None
        self.image_stack = None
        self.file_path = None

    def init(self, ui):
        """
        得到UI实例，对组件进行初始化配置
        """
        self.ui = ui
        # TODO 组件初始化 赋值操作

        # # 赋初值
        # self.ui.tk_input_account.insert(0, "8888")
        # # 设置为密码框
        # self.ui.tk_input_password.configure(show="*")
        # self.ui.tk_input_password.insert(0, "123456")

    def on_login(self, evt):
        # 登录按钮事件
        showinfo(title="提示", message="登录成功")

    def adjust_image_size(self):
        # 获取画布的大小
        canvas_width = self.ui.canvas.winfo_width()
        canvas_height = self.ui.canvas.winfo_height()
        print(canvas_height, canvas_width)
        original_width, original_height = self.image.size
        print(original_width, original_height)

        # 计算调整后的大小，保持纵横比
        if original_width > original_height:
            new_width = canvas_width
            new_height = int((canvas_width / original_width) * original_height)
        else:
            new_height = canvas_height
            new_width = int((canvas_height / original_height) * original_width)

            # 使用thumbnail方法调整图像大小
        self.image.thumbnail((new_width, new_height), Image.LANCZOS)

    def show_image(self, canvas=None, image=None):

        if image is not None:
            # 清除之前的内容
            canvas.delete("all")
            self.photo = ImageTk.PhotoImage(image)
            canvas.create_image(0, 0, anchor=tk.NW, tags="image", image=self.photo)

    def difference(self):
        # 显示调整后的图片
        # 恢复到上一个状态
        print("dui")
        image = self.image_stack[-1]
        while image == self.image:
            if len(self.image_stack) > 1:
                self.image_stack.pop()
            else:
                break
            image = self.image_stack[-1]

        self.show_image(self.ui.canvas, image)

    def cancel_difference(self):
        self.show_image(self.ui.canvas, self.image)

    def open_file(self, evt=None):
        # 弹出文件选择对话框
        self.file_path = filedialog.askopenfilename()

        if self.file_path:
            # 打开并调整图片大小以适应画布
            self.image_stack = []
            self.image = Image.open(self.file_path)
            self.image_stack.append(self.image)
            self.adjust_image_size()
            self.image_stack.append(self.image)
            self.show_image(self.ui.canvas, self.image)
            self.ui.file_path.config(text="当前图片路径：" + self.file_path)

    def undo(self, evt=None):
        if len(self.image_stack) >= 1:
            # 弹出当前图像

            # 恢复到上一个状态
            image = self.image_stack[-1]
            while image == self.image:
                if len(self.image_stack) > 1:
                    self.image_stack.pop()
                else:
                    break
                image = self.image_stack[-1]
            self.image = image

            # 当只剩下最初的原图时不能再出栈了，不然后面入栈其他的再撤销会找不到原图的

            # 显示图像
            self.show_image(self.ui.canvas, self.image)

    def save(self):
        # 保存图片功能
        if hasattr(self, 'image'):
            # 弹出文件选择对话框
            file_path = filedialog.asksaveasfilename(defaultextension=".png",
                                                     filetypes=[("PNG files", "*.png"),
                                                                ("JPEG files", "*.jpg"),
                                                                ("All files", "*.*")])

            if file_path:
                # 保存图片
                self.image.save(file_path)

    def cancel(self, evt=None):
        if self.image_stack is not None:
            self.image = self.image_stack[0]
            self.image_stack = []
            self.image_stack.append(self.image)
            self.adjust_image_size()
            self.show_image(self.ui.canvas, self.image)

    def on_mouse_motion(self, event):
        self.ui.canvas.delete("aa")
        self.ui.canvas.delete("bb")
        self.ui.canvas.delete("cc")
        self.ui.canvas.delete("dd")
        self.ui.canvas.create_line(self.start_x, self.start_y, event.x, self.start_y, fill="white", tags="aa",
                                   smooth=True)  # 绘制水平直线
        self.ui.canvas.create_line(self.start_x, event.y, event.x, event.y, fill="white", tags="aa",
                                   smooth=True)  # 绘制水平直线
        self.ui.canvas.create_line(event.x, self.start_y, event.x, event.y, fill="white", tags="bb",
                                   smooth=True)  # 绘制垂直直线
        self.ui.canvas.create_line(self.start_x, self.start_y, self.start_x, event.y, fill="white", tags="bb",
                                   smooth=True)  # 绘制垂直直线

    def on_mouse_press(self, event):
        self.start_x = event.x
        self.start_y = event.y
        self.ui.canvas.delete("aa")
        self.ui.canvas.delete("bb")
        self.ui.canvas.delete("cc")
        self.ui.canvas.delete("dd")

    def on_mouse_release(self, evt=None):
        image = self.image.crop((self.start_x, self.start_y, evt.x, evt.y))
        print("crop")
        self.apply(image)
        self.ui.canvas.unbind('<ButtonPress>')
        self.ui.canvas.unbind('<B1-Motion>')
        self.ui.canvas.unbind("<ButtonRelease-1>")

    def crop_image(self, evt=None):
        self.ui.canvas.bind('<ButtonPress>', self.on_mouse_press)
        self.ui.canvas.bind('<B1-Motion>', self.on_mouse_motion)
        self.ui.canvas.bind("<ButtonRelease-1>", self.on_mouse_release)
        pass

    def lightsense(self, evt=None):
        if hasattr(self, 'image'):
            popup = tk.Toplevel(self.ui)
            popup.title("光感调节")
            x = self.ui.winfo_rootx() + 650
            y = self.ui.winfo_rooty() + 50
            popup.geometry(f"+{x}+{y}")
            self.adjusted_image = None
            scale = tk.Scale(popup, from_=0, to=100, label="光感值", orient=tk.HORIZONTAL)
            scale.set(50)
            scale.pack(padx=20, pady=20)

            button = tk.Button(popup, text="应用", takefocus=False, command=self.apply)
            button.pack(padx=20, pady=20)

            def adjust_light_sense(img, a):
                a = np.float32(a - 50) / 80.0
                a = a * 255
                res = img.astype(np.float32)
                res = res + a * res / 255.0
                res = np.where(res > 255, 255, res)
                res = np.where(res < 0, 0, res)
                res = res.astype(np.uint8)
                return res

            def handle_lightsense(value):
                exposure_factor = float(value)
                if self.image is not None:
                    lightsense_adjusted = adjust_light_sense(np.array(self.image), exposure_factor)
                    self.adjusted_image = Image.fromarray(lightsense_adjusted)
                    self.show_image(self.ui.canvas, self.adjusted_image)
                else:
                    print("self.image is None")

            scale.config(command=handle_lightsense)

            def destroy_image():
                self.show_image()
                popup.destroy()

            popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def exposure(self, evt=None):
        if hasattr(self, 'image'):
            popup = tk.Toplevel(self.ui)
            popup.title("曝光调节")
            x = self.ui.winfo_rootx() + 650
            y = self.ui.winfo_rooty() + 50
            popup.geometry(f"+{x}+{y}")
            self.adjusted_image = None

            # 创建滑块和按钮
            scale = tk.Scale(popup, from_=0, to=100, resolution=0.1, label="曝光值", orient=tk.HORIZONTAL)
            scale.set(50)
            scale.pack(padx=20, pady=20)
            button = tk.Button(popup, text="应用", takefocus=False, command=self.apply)
            button.pack(padx=20, pady=20)

            def _adjust_exposure(img, b):
                # 曝光度调整 参数 b: 0~100
                b = np.float32(b - 50) / 20.0
                res = img.astype(np.float32)
                print(pow(2, b))
                res = res * pow(2, b)
                res = np.where(res > 255, 255, res)
                res = res.astype(np.uint8)
                return res

            def handle_exposure(value):
                exposure_factor = float(value)
                if self.image is not None:
                    exposure_adjusted = _adjust_exposure(np.array(self.image), exposure_factor)
                    self.adjusted_image = Image.fromarray(exposure_adjusted)
                    self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
                else:
                    print("self.image is None")

            # 监听滑块值变化
            scale.config(command=handle_exposure)

            # 关闭弹窗时销毁图像对象
            def destroy_image():
                self.show_image(self.ui.canvas, self.image)
                self.image_tk = None
                popup.destroy()

            popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def rotate_image(self, evt=None):
        if hasattr(self, 'image'):
            popup = tk.Toplevel(self.ui)
            popup.title("旋转调节")
            x = self.ui.winfo_rootx() + 650
            y = self.ui.winfo_rooty() + 50
            popup.geometry(f"+{x}+{y}")
            self.adjusted_image = None

            # 创建滑块和按钮
            scale = tk.Scale(popup, from_=0, to=360, label="旋转角度", orient=tk.HORIZONTAL)
            scale.set(0)
            scale.pack(padx=20, pady=20)
            button = tk.Button(popup, text="应用", takefocus=False, command=self.apply)
            button.pack(padx=20, pady=20)

            def handle_rotation(value):
                rotation_angle = float(value)
                if self.image is not None:
                    self.adjusted_image = self.image.rotate(rotation_angle, expand=False)

                    # 获取旋转后图像的尺寸
                    rotated_width, rotated_height = self.adjusted_image.size

                    # 计算缩放比例
                    scale_factor = min(self.ui.canvas.winfo_width() / rotated_width,
                                       self.ui.canvas.winfo_height() / rotated_height)
                    scaled_width = int(rotated_width * scale_factor)
                    scaled_height = int(rotated_height * scale_factor)

                    # 缩放图像
                    self.adjusted_image = self.adjusted_image.resize((scaled_width, scaled_height), Image.BILINEAR)

                    # 在画布上显示调整后的图像
                    self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
                else:
                    print("self.image is None")

            # 监听滑块值变化
            scale.config(command=handle_rotation)

            # 关闭弹窗时销毁图像对象
            def destroy_image():
                self.show_image(self.ui.canvas, self.image)
                self.image_tk = None
                popup.destroy()

            popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def image_transpose(self, evt=None):
        if self.image is None:
            print("NONE")
        image = self.image.transpose(Image.FLIP_LEFT_RIGHT)
        self.apply(image)

    def Image_Scaling(self, evt=None):
        def apply_scaling(event=None):
            try:
                scale = scale_slider.get()
                scale_factor = float(scale)
                if self.image is not None:
                    width = int(self.image.width * scale_factor)
                    height = int(self.image.height * scale_factor)
                    self.adjusted_image = self.image.resize((width, height))
                    self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
                else:
                    print("self.image is None")
            except ValueError:
                print("Invalid scale factor. Please enter a valid number.")

        if hasattr(self, 'image'):
            # 创建弹窗
            popup = tk.Toplevel(self.ui)
            popup.title("图像缩放")
            x = self.ui.winfo_rootx() + 650
            y = self.ui.winfo_rooty() + 50
            popup.geometry(f"+{x}+{y}")
            self.adjusted_image = None

            # 创建滑块和按钮
            scale_label = tk.Label(popup, text="缩放比例:")
            scale_label.pack(padx=20, pady=10)
            scale_slider = tk.Scale(popup, from_=0.1, to=2.0, resolution=0.1, orient=tk.HORIZONTAL,
                                    command=apply_scaling)
            scale_slider.set(1.0)
            scale_slider.pack(padx=20, pady=10)
            button = tk.Button(popup, text="应用", takefocus=False,
                               command=self.apply)
            button.pack(padx=20, pady=10)

            # 关闭弹窗时销毁图像对象
            def destroy_image():
                self.show_image(self.ui.canvas, self.image)
                self.image_tk = None
                popup.destroy()

            popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def apply_scaling(self, scale):
        try:
            scale_factor = float(scale)
            if self.image is not None:
                width = int(self.image.width * scale_factor)
                height = int(self.image.height * scale_factor)
                self.adjusted_image = self.image.resize((width, height))
                self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
            else:
                print("self.image is None")
        except ValueError:
            print("Invalid scale factor. Please enter a valid number.")

    def apply(self, image=None):

        if image != None:
            self.image = image
        else:
            self.image = self.adjusted_image
        # 入栈及时保存
        if self.image != self.image_stack[-1]:
            self.image_stack.append(self.image)
        self.show_image(self.ui.canvas, self.image)

    def contrast(self, evt=None):
        # 创建弹窗
        popup = tk.Toplevel(self.ui)
        popup.title("调节对比度")
        # 设置弹窗的位置在主窗体内
        x = self.ui.winfo_rootx() + 650  # 设置 x 坐标
        y = self.ui.winfo_rooty() + 50  # 设置 y 坐标
        popup.geometry(f"+{x}+{y}")  # 将弹窗定位到指定的位置
        self.adjusted_image = None
        # 创建滑块
        scale = tk.Scale(popup, from_=0, to=200, label="对比度", orient=HORIZONTAL)
        scale.set(100)
        scale.pack(padx=20, pady=20)
        button = tk.Button(popup, text="应用", takefocus=False, command=self.apply)
        button.pack(padx=20, pady=20)

        # 处理滑块值变化的函数
        def handle_contrast(value):
            # 应用对比度调整
            # 将滑块值转换为浮点数
            contrast_value = float(value) / 100.0
            if self.image is not None:
                self.adjusted_image = ImageEnhance.Contrast(self.image).enhance(contrast_value)
                self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
            else:
                print("self.image is none")

        # 监听滑块值变化
        scale.config(command=handle_contrast)

        # 关闭弹窗时销毁图像对象
        def destroy_image():
            self.show_image(self.ui.canvas, self.image)
            self.image_tk = None
            popup.destroy()

        popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def hue(self, evt=None):
        def adjust_hue(image, hue_shift):
            # 将图像转换为NumPy数组
            np_image = np.array(image)

            # 将图像转换为HSV颜色空间
            hsv_image = cv2.cvtColor(np_image, cv2.COLOR_RGB2HSV)

            # 调整色调
            hsv_image[:, :, 0] = (hsv_image[:, :, 0].astype(int) + hue_shift) % 180

            # 转换回RGB颜色空间
            rgb_image = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2RGB)

            # 创建调整后的图像
            adjusted_image = Image.fromarray(rgb_image)

            return adjusted_image

        def handle_hue(value):
            # 应用色调调整
            # 将滑块值转换为整数
            hue_shift = int(value)
            if self.image is not None:
                self.adjusted_image = adjust_hue(self.image, hue_shift)
                self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
            else:
                print("self.image is None")

        # 创建弹窗
        popup = tk.Toplevel(self.ui)
        popup.title("调节色调")
        # 设置弹窗的位置在主窗体内
        x = self.ui.winfo_rootx() + 650  # 设置 x 坐标
        y = self.ui.winfo_rooty() + 50  # 设置 y 坐标
        popup.geometry(f"+{x}+{y}")  # 将弹窗定位到指定的位置
        self.adjusted_image = None
        # 创建滑块
        scale = tk.Scale(popup, from_=-180, to=180, label="色调调节", orient=tk.HORIZONTAL)
        scale.set(0)
        scale.pack(padx=20, pady=20)
        button = tk.Button(popup, text="应用", takefocus=False, command=self.apply)
        button.pack(padx=20, pady=20)

        # 监听滑块值变化
        scale.config(command=handle_hue)

        # 关闭弹窗时销毁图像对象
        def destroy_image():
            self.show_image(self.ui.canvas, self.image)
            self.image_tk = None
            popup.destroy()

        popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def adjust_equalize(self, evt=None):
        # 直方图均衡化功能
        if hasattr(self, 'image'):
            self.adjusted_image = ImageOps.equalize(self.image)
            self.apply(self.adjusted_image)
            self.show_image(self.ui.canvas, self.adjusted_image)

    def smooth(self, evt=None):
        def smooth_image(image, smooth_value):
            smooth_value = int(smooth_value)
            img_np = np.array(image)
            img_cv2 = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)
            if smooth_value % 2 == 0:
                smooth_value += 1
            smooth_value = smooth_value if smooth_value % 2 != 0 else smooth_value + 1  #
            if smooth_value < 0.1:
                return image
            smoothed_img = cv2.GaussianBlur(img_cv2, (smooth_value, smooth_value), 0)
            res_img = Image.fromarray(cv2.cvtColor(smoothed_img, cv2.COLOR_BGR2RGB))

            return res_img

        # 创建弹窗
        popup = tk.Toplevel(self.ui)
        popup.title("平滑调整")
        # 设置弹窗的位置在主窗体内
        x = self.ui.winfo_rootx() + 650  # 设置 x 坐标
        y = self.ui.winfo_rooty() + 50  # 设置 y 坐标
        popup.geometry(f"+{x}+{y}")  # 将弹窗定位到指定的位置
        self.adjusted_image = None
        # 创建滑块
        scale = tk.Scale(popup, from_=0, to=100, label="平滑强度", orient=tk.HORIZONTAL)
        scale.set(0)
        scale.pack(padx=20, pady=20)
        button = tk.Button(popup, text="应用", takefocus=False, command=self.apply)
        button.pack(padx=20, pady=20)

        # 处理滑块值变化的函数
        def handle_smooth(value):
            # 应用锐化调整
            # 将滑块值转换为整数
            sharpen_strength = int(value)
            if self.image is not None:
                sharpened_image = smooth_image(self.image, sharpen_strength)
                self.adjusted_image = sharpened_image
                self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
            else:
                print("self.image is None")

        # 监听滑块值变化
        scale.config(command=handle_smooth)

        # 关闭弹窗时销毁图像对象
        def destroy_image():
            self.show_image(self.ui.canvas, self.image)
            self.image_tk = None
            popup.destroy()

        popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def sharpen(self, evt=None):
        def sharpen_image(image, strength):
            if strength < 0.1:
                return image
            sharpen_value = max(strength, 0) / 100.0  # 将取值截断到 0 到 1 之间
            # 定义锐化卷积核
            kernel = np.array([[-1, -1, -1],
                               [-1, 9 + sharpen_value, -1],
                               [-1, -1, -1]])

            # 将图像转换为NumPy数组
            np_image = np.array(image)

            # 对图像进行卷积操作
            sharpened_image = cv2.filter2D(np_image, -1, kernel)

            # 创建锐化后的图像
            sharpened_image = Image.fromarray(sharpened_image)

            return sharpened_image

        # 创建弹窗
        popup = tk.Toplevel(self.ui)
        popup.title("锐化调整")
        # 设置弹窗的位置在主窗体内
        x = self.ui.winfo_rootx() + 650  # 设置 x 坐标
        y = self.ui.winfo_rooty() + 50  # 设置 y 坐标
        popup.geometry(f"+{x}+{y}")  # 将弹窗定位到指定的位置
        self.adjusted_image = None
        # 创建滑块
        scale = tk.Scale(popup, from_=0, to=100, label="锐化强度", orient=tk.HORIZONTAL)
        scale.set(0)
        scale.pack(padx=20, pady=20)
        button = tk.Button(popup, text="应用", takefocus=False, command=self.apply)
        button.pack(padx=20, pady=20)

        # 处理滑块值变化的函数
        def handle_sharpen(value):
            # 应用锐化调整
            # 将滑块值转换为整数
            sharpen_strength = int(value)
            if self.image is not None:
                sharpened_image = sharpen_image(self.image, sharpen_strength)
                self.adjusted_image = sharpened_image
                self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
            else:
                print("self.image is None")

        # 监听滑块值变化
        scale.config(command=handle_sharpen)

        # 关闭弹窗时销毁图像对象
        def destroy_image():
            self.show_image(self.ui.canvas, self.image)
            self.image_tk = None
            popup.destroy()

        popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def color_temperature(self, evt=None):
        # 旧算法
        def adjust_temperature_1(image, temperature):
            original_image = image.convert("RGB")
            r, g, b = original_image.split()
            temperature += 100
            temperature = temperature / 100.0
            print(temperature)

            # 避免除以零错误
            adjusted_b = b.point(lambda p: p * (1 / temperature) if temperature != 0 else p)

            # 调整红色通道
            adjusted_r = r.point(lambda p: p * temperature)

            # 合并通道
            adjusted_image = Image.merge("RGB", (adjusted_r, g, adjusted_b))

            return adjusted_image

        # #新算法
        # def adjust_temperature(self, value, evt=None):
        #     if self.last_op != inspect.currentframe().f_code.co_name:
        #         self.image_back = self.image
        #     if hasattr(self, 'image_back') and self.image is not None:
        #         temperature = float(value) / 100.0
        #
        #         # 避免除以零错误
        #         temperature = max(temperature, 0.001)
        #
        #         self.image = self.adjust_temperature_1(temperature)
        #         self.show_image(flag=1)
        #         self.last_op = inspect.currentframe().f_code.co_name
        def adjust_color_temperature(image, temperature):
            # 将图像转换为NumPy数组
            np_image = np.array(image)

            # 将图像转换为LAB颜色空间
            lab_image = cv2.cvtColor(np_image, cv2.COLOR_RGB2LAB)

            # 调整色温
            lab_image[:, :, 0] = np.clip(lab_image[:, :, 0].astype(float) + temperature, 0, 255)

            # 转换回RGB颜色空间
            rgb_image = cv2.cvtColor(lab_image, cv2.COLOR_LAB2RGB)

            # 创建调整后的图像
            adjusted_image = Image.fromarray(rgb_image.astype(np.uint8))

            return adjusted_image

        def handle_color_temperature(value):
            # 应用色温调整
            # 将滑块值转换为浮点数
            temperature = float(value)
            if self.image is not None:
                # self.adjusted_image = adjust_color_temperature(self.image, temperature)
                # 采用旧算法
                self.adjusted_image = adjust_temperature_1(self.image, temperature)
                self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
            else:
                print("self.image is None")

        # 创建弹窗
        popup = tk.Toplevel(self.ui)
        popup.title("调节色温")
        # 设置弹窗的位置在主窗体内
        x = self.ui.winfo_rootx() + 650  # 设置 x 坐标
        y = self.ui.winfo_rooty() + 50  # 设置 y 坐标
        popup.geometry(f"+{x}+{y}")  # 将弹窗定位到指定的位置
        self.adjusted_image = None
        # 创建滑块
        scale = tk.Scale(popup, from_=-100, to=100, label="色温调节", orient=tk.HORIZONTAL)
        scale.set(0)
        scale.pack(padx=20, pady=20)
        button = tk.Button(popup, text="应用", takefocus=False, command=self.apply)
        button.pack(padx=20, pady=20)

        # 监听滑块值变化
        scale.config(command=handle_color_temperature)

        # 关闭弹窗时销毁图像对象
        def destroy_image():
            self.show_image(self.ui.canvas, self.image)
            self.image_tk = None
            popup.destroy()

        popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def adjust_hsl(self, evt=None):

        def adjust_hsl_values_color(image, hue_shift, saturation_scale, luminance_scale, selected_color="洋红"):
            # 将图像转换为 NumPy 数组
            np_image = np.array(image)

            # 将图像转换为 HSL 颜色空间
            hsl_image = cv2.cvtColor(np_image, cv2.COLOR_RGB2HLS)

            # 定义颜色通道索引字典
            color_channels = {'红色': 0, '绿色': 1, '蓝色': 2, '青色': 3, '洋红': 4, '黄色': 5}

            # 根据选择的颜色通道进行 HSL 调整
            selected_channel = color_channels[selected_color]

            # 调整色调
            hsl_image[:, :, selected_channel] = (hsl_image[:, :, selected_channel].astype(int) + hue_shift) % 360

            # 调整饱和度
            hsl_image[:, :, 2] = np.where(
                np.isclose(hsl_image[:, :, selected_channel], hsl_image[:, :, 2]),
                np.clip(hsl_image[:, :, 2].astype(float) * saturation_scale, 0, 255),
                hsl_image[:, :, 2]
            )

            # 调整亮度
            hsl_image[:, :, 1] = np.where(
                np.isclose(hsl_image[:, :, selected_channel], hsl_image[:, :, 1]),
                np.clip(hsl_image[:, :, 1].astype(float) * luminance_scale, 0, 255),
                hsl_image[:, :, 1]
            )

            # 转换回 RGB 颜色空间
            rgb_image = cv2.cvtColor(hsl_image, cv2.COLOR_HLS2RGB)

            # 创建调整后的图像
            adjusted_image = Image.fromarray(rgb_image.astype(np.uint8))

            return adjusted_image

        def adjust_hsl_values(image, hue_shift, saturation_scale, luminance_scale):
            # 将图像转换为 NumPy 数组
            np_image = np.array(image)

            # 将图像转换为 HSL 颜色空间
            hsl_image = cv2.cvtColor(np_image, cv2.COLOR_RGB2HLS)

            # 调整色调
            hsl_image[:, :, 0] = (hsl_image[:, :, 0].astype(int) + hue_shift) % 360

            # 调整饱和度
            hsl_image[:, :, 2] = np.clip(hsl_image[:, :, 2].astype(float) * saturation_scale, 0, 255)

            # 调整亮度
            hsl_image[:, :, 1] = np.clip(hsl_image[:, :, 1].astype(float) * luminance_scale, 0, 255)

            # 转换回 RGB 颜色空间
            rgb_image = cv2.cvtColor(hsl_image, cv2.COLOR_HLS2RGB)

            # 创建调整后的图像
            adjusted_image = Image.fromarray(rgb_image.astype(np.uint8))

            return adjusted_image

        def handle_hsl(hue_value, saturation_value, luminance_value):
            # 将滑块值转换为相应的调整参数
            hue_shift = int(hue_value)
            saturation_scale = float(saturation_value)
            luminance_scale = float(luminance_value)

            if self.image is not None:
                self.adjusted_image = adjust_hsl_values(self.image, hue_shift, saturation_scale, luminance_scale)
                self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
            else:
                print("self.image is None")

        # 创建弹窗
        popup = tk.Toplevel(self.ui)
        popup.title("调节HSL")
        # 设置弹窗的位置在主窗体内
        x = self.ui.winfo_rootx() + 650  # 设置 x 坐标
        y = self.ui.winfo_rooty() + 50  # 设置 y 坐标
        popup.geometry(f"+{x}+{y}")  # 将弹窗定位到指定的位置
        self.adjusted_image = None
        # 创建滑块
        hue_scale = tk.Scale(popup, from_=-30, to=30, label="色调调节", orient=tk.HORIZONTAL)
        hue_scale.set(0)
        hue_scale.pack(padx=20, pady=10)

        saturation_scale = tk.Scale(popup, from_=0, to=2, label="饱和度调节", orient=tk.HORIZONTAL, resolution=0.01)
        saturation_scale.set(1)
        saturation_scale.pack(padx=20, pady=10)

        luminance_scale = tk.Scale(popup, from_=0, to=2, label="亮度调节", orient=tk.HORIZONTAL, resolution=0.01)
        luminance_scale.set(1)
        luminance_scale.pack(padx=20, pady=10)

        button = tk.Button(popup, text="应用", takefocus=False, command=self.apply)
        button.pack(padx=20, pady=10)

        # 监听滑块值变化
        hue_scale.config(command=lambda value: handle_hsl(value, saturation_scale.get(), luminance_scale.get()))
        saturation_scale.config(command=lambda value: handle_hsl(hue_scale.get(), value, luminance_scale.get()))
        luminance_scale.config(command=lambda value: handle_hsl(hue_scale.get(), saturation_scale.get(), value))

        # 关闭弹窗时销毁图像对象
        def destroy_image():
            self.show_image(self.ui.canvas, self.image)
            self.image_tk = None
            popup.destroy()

        popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def saturation(self, evt=None):
        def adjust_saturation(image, saturation_factor):
            # 将图像转换为NumPy数组
            np_image = np.array(image)

            # 将图像转换为HSV颜色空间
            hsv_image = cv2.cvtColor(np_image, cv2.COLOR_RGB2HSV)

            # 调整饱和度
            hsv_image[:, :, 1] = np.clip(hsv_image[:, :, 1].astype(float) * saturation_factor, 0, 255)

            # 转换回RGB颜色空间
            rgb_image = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2RGB)

            # 创建调整后的图像
            adjusted_image = Image.fromarray(rgb_image.astype(np.uint8))

            return adjusted_image

        def handle_saturation(value):
            # 应用饱和度调整
            # 将滑块值转换为浮点数
            saturation_factor = float(value)
            if self.image is not None:
                self.adjusted_image = adjust_saturation(self.image, saturation_factor)
                self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
            else:
                print("self.image is None")

        # 创建弹窗
        popup = tk.Toplevel(self.ui)
        popup.title("调节饱和度")
        # 设置弹窗的位置在主窗体内
        x = self.ui.winfo_rootx() + 650  # 设置 x 坐标
        y = self.ui.winfo_rooty() + 50  # 设置 y 坐标
        popup.geometry(f"+{x}+{y}")  # 将弹窗定位到指定的位置
        self.adjusted_image = None
        # 创建滑块
        scale = tk.Scale(popup, from_=0, to=2, label="饱和度调节", orient=tk.HORIZONTAL, resolution=0.01)
        scale.set(1)
        scale.pack(padx=20, pady=20)
        button = tk.Button(popup, text="应用", takefocus=False, command=self.apply)
        button.pack(padx=20, pady=20)

        # 监听滑块值变化
        scale.config(command=handle_saturation)

        # 关闭弹窗时销毁图像对象
        def destroy_image():
            self.show_image(self.ui.canvas, self.image)
            self.image_tk = None
            popup.destroy()

        popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def brightness(self, evt=None):
        # 创建弹窗
        popup = tk.Toplevel(self.ui)
        popup.title("调节亮度")
        x = self.ui.winfo_rootx() + 650
        y = self.ui.winfo_rooty() + 50
        popup.geometry(f"+{x}+{y}")
        self.adjusted_image = None

        # 创建滑块
        scale = tk.Scale(popup, from_=0, to=200, label="亮度", orient=tk.HORIZONTAL)
        scale.set(100)
        scale.pack(padx=20, pady=20)
        button = tk.Button(popup, text="应用", takefocus=False, command=self.apply)
        button.pack(padx=20, pady=20)

        # 处理滑块值变化的函数
        def handle_brightness(value):
            # 应用亮度调整
            if self.image is not None:
                brightness_factor = float(value) / 100.0
                # 在增强亮度之前检查 self.image 是否不为 None
                self.adjusted_image = ImageEnhance.Brightness(self.image).enhance(brightness_factor)
                self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
            else:
                print("self.image is none")

        # 监听滑块值变化
        scale.config(command=handle_brightness)

        # 关闭弹窗时销毁图像对象
        def destroy_image():
            self.show_image(self.ui.canvas, self.image)
            self.image_tk = None
            popup.destroy()

        popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def tools(self, evt=None):
        pass

    def watermark(self, evt=None):
        def add_watermark_to_image():
            if self.image is not None and self.watermark_image_back is not None:
                # 打开背景图和水印图
                background = self.image.convert('RGBA')
                watermark = self.watermark_image_back.convert('RGBA')

                # 调整水印大小以适应背景图
                watermark = watermark.resize(background.size, Image.LANCZOS)

                # 将水印叠加到背景图上
                alpha = 0.1
                result = Image.blend(background, watermark, alpha)

                # 显示结果
                self.image = result
                self.show_image(self.ui.canvas, self.image)

        # 创建弹窗
        popup = tk.Toplevel(self.ui)
        popup.title("添加水印图片")

        # 设置弹窗的位置在主窗体内
        x = self.ui.winfo_rootx() + 650  # 设置 x 坐标
        y = self.ui.winfo_rooty() + 50  # 设置 y 坐标
        popup.geometry(f"+{x}+{y}")  # 将弹窗定位到指定的位置

        # 创建按钮打开水印图片
        def open_watermark_image():
            self.watermark_image_back = Image.open(
                tk.filedialog.askopenfilename(filetypes=[("Image Files", "*.png;*.jpg;*.jpeg")]))
            if self.watermark_image_back:
                print("水印图片已选择：", self.watermark_image_back)
                # 在标签上显示图片
                self.watermark_image_preview_tk = ImageTk.PhotoImage(self.watermark_image_back)
                watermark_preview.configure(image=self.watermark_image_preview_tk)
                watermark_preview.image = self.watermark_image_preview_tk

        open_button = tk.Button(popup, text="打开水印图片", command=open_watermark_image)
        open_button.pack(padx=20, pady=10)

        # 创建标签显示水印图片预览
        popup.watermark_image_preview_tk = None
        watermark_preview = tk.Label(popup)
        watermark_preview.pack(padx=20, pady=10)

        # 创建按钮添加水印图片
        add_button = tk.Button(popup, text="添加水印图片", command=add_watermark_to_image)
        add_button.pack(padx=20, pady=10)

        # 关闭弹窗时销毁图像对象
        def destroy_image():
            self.show_image(self.ui.canvas, self.image)
            self.image_tk = None
            self.watermark_image_back = None
            popup.destroy()

        popup.protocol("WM_DELETE_WINDOW", destroy_image)

    def curve_toning(self):
        # 创建弹窗
        popup = tk.Toplevel(self.ui, width=512, height=512)
        popup.title("曲线调色")
        x = self.ui.winfo_rootx() + 650
        y = self.ui.winfo_rooty() + 50
        popup.geometry(f"+{x}+{y}")
        self.adjusted_image = None
        color_label = tk.Label(popup, text="通道")
        color_label.pack()  # #将下拉菜单绑定到窗体

        xVariable = tkinter.StringVar()  # #创建变量，便于取值

        com = Combobox(popup, textvariable=xVariable)  # #创建下拉菜单
        com.pack()  # #将下拉菜单绑定到窗体
        com["value"] = ("红色", "蓝色", "绿色", "明度")  # #给下拉菜单设定值
        com.current(0)  # #设定下拉菜单的默认值为第3个，即山东

        control_points = [(0, 512), (256, 256), (512, 0)]
        fixed_indexes = [0, 2]

        def xFunc(event):
            nonlocal control_points
            control_points = [(0, 512), (256, 256), (512, 0)]
            draw_curve(canvas, updata="notNone")
            self.apply(self.adjusted_image)
            print(com.get())  # #获取选中的值方法1
            print(xVariable.get())  # #获取选中的值方法2

        com.bind("<<ComboboxSelected>>", xFunc)  # #给下拉菜单绑定事件

        # 曲线控制点的初始坐标
        # control_points = [(0, 512), (166.666, 333.333), (333.333, 166.666), (500, 0)]
        # control_points = [(0, 512), (170.666, 341.333), (341.333, 170.666), (512, 0)]

        flag = 0

        def draw_curve(canvas, updata=None):
            # 清空画布
            canvas.delete("curve")
            canvas.delete("point_1")
            canvas.delete("point_2")

            # 绘制曲线
            canvas.create_line(control_points, smooth=True, width=2, tags="curve")

            # 绘制控制点
            for i, (x, y) in enumerate(control_points):
                if i in fixed_indexes:
                    # 固定的端点使用不同的颜色
                    canvas.create_oval(x - 1, y - 1, x + 1, y + 1, fill="green", outline="black", tags="point_1")
                else:
                    canvas.create_oval(x - 1, y - 1, x + 1, y + 1, fill="red", outline="black", tags="point_2")

            i = 0
            curves_adjustment = CurvesAdjustment()
            if updata is not None:
                return
            for x in range(0, 256):
                x = x * 2
                t = opt.newton(equation, 0, args=(control_points[0][0], control_points[1][0], control_points[2][0], x))
                y = (1 - t) ** 2 * control_points[0][1] + 2 * t * (1 - t) * control_points[1][1] + control_points[2][
                    1] * t ** 2
                x = int(x / 2)
                # print(control_points)
                # print(f"xx = {x}")
                # print(f"tt = {t}")

                y = int((512 - y) / 2)

                if y < 0:
                    y = 0
                    # print("BUG---------------------")
                if y > 255:
                    y = 255
                if x < 0:
                    print("BUG++")
                # print(f"yy={y}")
                # distance = distance_to_curve(x, 0, point=1)
                if com.get() == "红色":
                    curves_adjustment.red_curve.add_point(x, y)
                if com.get() == "蓝色":
                    curves_adjustment.blue_curve.add_point(x, y)
                if com.get() == "绿色":
                    curves_adjustment.green_curve.add_point(x, y)
                if com.get() == "明度":
                    curves_adjustment.red_curve.add_point(x, y)
                    curves_adjustment.blue_curve.add_point(x, y)
                    curves_adjustment.green_curve.add_point(x, y)

                # dis = math.fabs(distance)
            numpy_image = np.array(self.image)
            # 将NumPy数组转换为OpenCV图像
            numpy_image = cv2.cvtColor(numpy_image, cv2.COLOR_RGB2BGR)
            self.adjusted_image = curves_adjustment.adjust_image(numpy_image)
            self.adjusted_image = Image.fromarray(self.adjusted_image)
            self.show_image(self.ui.canvas, self.adjusted_image)

        def move_point(event):
            nonlocal flag
            # print(flag)
            if flag == 0:
                return
            # else:
            # print("flag=1")
            # 查找最接近鼠标点击位置的控制点，但不包括固定的端点
            closest_point = min([p for i, p in enumerate(control_points) if i not in fixed_indexes],
                                key=lambda p: ((p[0] - event.x) ** 2 + (p[1] - event.y) ** 2) ** 0.5)

            # 计算鼠标点击位置到曲线的距离
            distance = distance_to_curve(event.x, event.y)
            dis = math.fabs(distance)

            # print(f"distance={distance}")

            def handle_brightness(value):
                # 应用亮度调整
                if self.image is not None:
                    brightness_factor = float(value) / 100.0
                    # 在增强亮度之前检查 self.image 是否不为 None
                    self.adjusted_image = ImageEnhance.Brightness(self.image).enhance(brightness_factor)
                    self.show_image(canvas=self.ui.canvas, image=self.adjusted_image)
                else:
                    print("self.image is none")

            handle_brightness(distance + 100)

            # 如果鼠标点击位置在曲线上，则输出点击的位置

            # 更新控制点的坐标为鼠标位置
            closest_point_index = control_points.index(closest_point)
            if event.x < 0:
                event.x = 0
            control_points[closest_point_index] = (event.x, event.y)
            # 重新绘制曲线
            draw_curve(canvas)

        def distance_to_curve(x, y, point=None):
            if x < 0:
                x = 0
            if x > 512:
                x = 512
            # 计算鼠标点击位置到曲线的最短距离
            min_distance = float("inf")

            # 已知的 y 值和参数
            a0 = control_points[0][0]
            a1 = control_points[1][0]
            a2 = control_points[2][0]
            # a3 = control_points[3][0]

            # 使用牛顿法求解方程
            x0 = 0.0  # 初始估计值
            t = opt.newton(equation, x0, args=(a0, a1, a2, x))
            # print(f"x={x}")
            # print(f"t={t}")

            a0 = control_points[0][1]
            a1 = control_points[1][1]
            a2 = control_points[2][1]
            # a3 = control_points[3][1]

            res = (1 - t) ** 2 * a0 + 2 * t * (1 - t) * a1 + a2 * t ** 2
            # print(f"y={res}")

            if point is not None:
                # print("calculate index")
                return res

            return res - y

        # 创建画布
        canvas = tk.Canvas(popup, width=512, height=512)
        canvas.pack()

        def draw_grid(canvas, width, height, rows, columns):
            # 计算每个单元格的宽度和高度
            cell_width = width // columns
            cell_height = height // rows

            # 绘制水平线条
            for row in range(rows + 1):
                y = row * cell_height
                canvas.create_line(0, y, width, y)

            # 绘制垂直线条
            for col in range(columns + 1):
                x = col * cell_width
                canvas.create_line(x, 0, x, height)

        # 绘制初始曲线
        draw_curve(canvas)

        # 绘制网格
        draw_grid(canvas, 512, 512, 8, 8)

        # 绑定鼠标事件
        canvas.bind("<B1-Motion>", move_point)

        def click_point(event):
            nonlocal flag
            print("鼠标单击位置:", event.x, event.y)
            distance = distance_to_curve(event.x, event.y)
            dis = math.fabs(distance)
            # print(f"distance={dis}")
            if dis < 30:
                flag = 1
                print("激活", flag)
            else:
                flag = 0
            # 点击事件处理逻辑
            pass

        # 绑定鼠标左键单击事件
        canvas.bind("<Button-1>", click_point)

        def release_point(event):
            nonlocal flag
            flag = 0
            print("恢复", flag)

            # 点击后释放逻辑
            pass

        # 绑定鼠标左键点击后释放事件
        canvas.bind("<ButtonRelease-1>", release_point)

        # 运行主循环
        popup.mainloop()
        print("over.....")

    def add_text(self, evt=None):

        # 创建 Frame 实例
        frame = tk.Frame(self.ui, width=200, height=150, bg="white")

        # 计算 Frame 的居中位置
        window_width = self.ui.winfo_width()
        window_height = self.ui.winfo_height()
        frame_width = frame.winfo_reqwidth()
        frame_height = frame.winfo_reqheight()
        x = (window_width - frame_width) // 2
        y = (window_height - frame_height) // 2
        y = self.ui.canvas.winfo_height()

        # 将 Frame 居中添加到主窗口中
        frame.place(x=x, y=y)

        # 在 Frame 中添加其他组件或布局
        label = tk.Label(frame, text="添加文字面板")
        label.pack()

        draggable_text = None

        font_size = 12

        # 根据需要添加其他组件或布局

        def close_frame():
            nonlocal draggable_text
            draggable_text.destroy()
            self.ui.canvas.unbind("<MouseWheel>")
            if self.image is None:
                print("bug")
                self.image = draggable_text.image
            draggable_text = None
            frame.destroy()  # 销毁 Frame

        def adjust_font_size(event=None):
            if self.image is None:
                print("NU")
            x_1 = self.ui.canvas.canvasx(event.x)
            y_1 = self.ui.canvas.canvasy(event.y)
            print(x_1, y_1)
            disx = x_1 - draggable_text.drag_data["x"]
            disx = math.fabs(disx)
            disy = y_1 - draggable_text.drag_data["y"]
            disy = math.fabs(disy)
            nonlocal font_size
            if disx < 20 and disy < 20:

                # items = self.ui.canvas.find_overlapping(x, y, x, y)
                # if draggable_text.text_widget in items:
                delta = event.delta
                if delta > 0:
                    font_size += 1  # 增加字体大小
                else:
                    font_size -= 1  # 减小字体大小
                if font_size < 1:
                    font_size = 1
                self.ui.canvas.itemconfigure(draggable_text.text_widget, font=("Arial", font_size))
                print("test")
            #     self.canvas.itemconfigure(self.text_widget, font=("Arial", self.font_size))

        def clear_default_text(event=None):
            if self.ui.ipt.get() == "输入文字":
                self.ui.ipt.delete(0, tk.END)

        def restore_default_text(event=None):
            if not self.ui.ipt.get():
                self.ui.ipt.insert(0, "输入文字")

        def add_text_fina():
            text = self.ui.ipt.get()
            print(text)
            print(self.ui.canvas.winfo_x(), self.ui.canvas.winfo_y())
            nonlocal draggable_text
            draggable_text = DraggableText(self.ui.canvas, text, self.ui.canvas.winfo_x() + 200,
                                           self.ui.canvas.winfo_y() + 200, self.image)

            draggable_text.on_release(image=self.image)
            if self.image is None:
                print("NULL")
            self.ui.canvas.bind("<MouseWheel>", adjust_font_size)
            if self.image is None:
                print("NONE")

            self.apply()

        self.ui.ipt = tk.Entry(frame)
        self.ui.ipt.insert(0, "输入文字")
        self.ui.ipt.bind("<FocusIn>", clear_default_text)
        self.ui.ipt.bind("<FocusOut>", restore_default_text)
        self.ui.ipt.pack(side=tk.TOP)
        self.ui.add_button = tk.Button(frame, text="添加", takefocus=False, command=add_text_fina)
        if self.image is None:
            print("NUssssLL")
        close_button = tk.Button(frame, text="关闭", takefocus=False, command=close_frame)
        self.ui.add_button.pack(side=tk.LEFT)
        close_button.pack(side=tk.RIGHT)

        if self.image is None:
            print("saaaaaaa")
        else:
            print("NONULL")

    def about(self, evt=None):
        pass

    def hint(self, evt=None):
        pass
